/**
@author		Jong Min, Lee
@date		  02/09/2014
@brief		study tab control

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#pragma once

#include <list>
#include "Taurus_Util/Macros.h"
#include "Taurus_Util/TUTypes.h"

typedef struct tagStudyTabItem
{
  CString theTitle;
  
  CString theToolTip;

  CRect rect;

  int width;
}CStudyTabItem;

class CStudyTab;

/**
@brief		tab draw base class
*/
struct CStudyTabDraw
{
  virtual void drawCtrlBack(CStudyTab& tabCtrl, CDC& dc) {}

  virtual void drawItem(CStudyTab& tabCtrl, CDC& dc, const CStudyTabItem& item) {}

  virtual void drawCloseButton(CStudyTab& tabCtrl, 
                               CDC& dc, 
                               const CRect& rect, 
                               BOOL bHover, 
                               BOOL bPushed) {}

  virtual void drawMenuButton(CStudyTab& tabCtrl, 
                              CDC& dc, 
                              const CRect& rect, 
                              BOOL isHovered, 
                              BOOL isPushed, 
                              BOOL isPartialView) {}

  virtual void drawScrollLeftButton(CStudyTab& tabCtrl, 
                                    CDC& dc, 
                                    const CRect& rect, 
                                    BOOL isHovered, 
                                    BOOL isPushed, 
                                    BOOL isPartialView) {}

  virtual void drawScrollRightButton(CStudyTab& tabCtrl, 
                                     CDC& dc, 
                                     const CRect& rect, 
                                     BOOL isHovered, 
                                     BOOL isPushed, 
                                     BOOL isPartialView) {}
};

struct IStudyTabRearrange
{
  virtual CRect getItemHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base) = 0;

  virtual CRect getLeftScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base) = 0;

  virtual CRect getRightScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base) = 0;

  virtual CRect getMenuBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base) = 0;

  virtual CRect getCloseBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base) = 0;
};

struct IStudyTabBehavior 
{
  virtual const CStudyTabItem* hitTest(CStudyTab& tabCtrl, IStudyTabBehavior& base, const CPoint& point) = 0;
};

struct IStudyTabToolTip
{
  virtual CToolTipCtrl* createToolTip(CStudyTab& tabCtrl, IStudyTabToolTip& base) = 0;
};

struct IStudyTabStyle
{
  virtual CStudyTabDraw* getDrawManager() = 0;
  virtual IStudyTabRearrange* getRearrangeManager() = 0;
  virtual IStudyTabBehavior* getBehaviorManager() = 0;
  virtual IStudyTabToolTip* getToolTipManager() = 0;
};

struct CStudyTabRearrangeStub : public IStudyTabRearrange
{
  virtual CRect getItemHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

  virtual CRect getLeftScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

  virtual CRect getRightScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

  virtual CRect getMenuBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

  virtual CRect getCloseBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);
};

struct CStudyTabBehaviorStub : public IStudyTabBehavior
{
  virtual const CStudyTabItem* hitTest(CStudyTab& tabCtrl, IStudyTabBehavior& base, const CPoint& point);
};

struct CStudyTabStyleBase : public IStudyTabStyle, public CStudyTabDraw
{
  //IStudyTabStyle
  virtual CStudyTabDraw* getDrawManager();
  virtual IStudyTabRearrange* getRearrangeManager();
  virtual IStudyTabBehavior* getBehaviorManager();
  virtual IStudyTabToolTip* getToolTipManager();

protected:
  virtual void drawCtrlBack(CStudyTab& tabCtrl, CDC& dc);

  virtual void drawItem(CStudyTab& tabCtrl, CDC& dc, const CStudyTabItem& item);

  virtual void drawCloseButton(CStudyTab& tabCtrl, CDC& dc, const CRect& rect, BOOL bHover, BOOL bPushed);

  virtual void drawMenuButton(CStudyTab& tabCtrl, CDC& dc, const CRect& rect, BOOL isHovered, BOOL isPushed, BOOL isPartialView);

  virtual void drawScrollLeftButton(CStudyTab& tabCtrl, CDC& dc, const CRect& rect, BOOL isHovered, BOOL isPushed, BOOL isPartialView);

  virtual void drawScrollRightButton(CStudyTab& tabCtrl, CDC& dc, const CRect& rect, BOOL isHovered, BOOL isPushed, BOOL isPartialView);

  virtual COLORREF getButtonMarkerColor(CStudyTab& tabCtrl, BOOL isHovered, BOOL isPushed);

  virtual void drawItemBK(CStudyTab& tabCtrl, CDC& dc, const CStudyTabItem& item);

  virtual void drawItemTitle(CStudyTab& tabCtrl, CDC& dc, const CStudyTabItem& item);

  virtual void drawButtonFrame(CStudyTab& tabCtrl, CDC& dc, const CRect& rect, BOOL isHover, BOOL isPushed);

  static void drawMarker(CDC& dc, const CRect& rect, CImageList* imageList, int imageIndex, COLORREF color);

  static BOOL drawMarker(CDC& dc, const CRect& rect, HBITMAP hbmpMask, COLORREF color);
};

/**
@brief		study tab control
*/
class CStudyTab : public CWnd
{
	DECLARE_DYNAMIC(CStudyTab)

public:

  typedef struct tagCreateParams
  {
    MonitorResolutionType theResType;

    unsigned int theMonitorIndex;
  }CreateParams;

public:
  /**
  @brief		default constructor
  */
	CStudyTab();

  /**
  @brief		destructor
  */
	virtual ~CStudyTab();

  /**
  @brief		remove all items
  */
  void removeAllItems();

  /**
  @brief		rearrange and redraw control
  @param		bRedraw flag indicating whether study tab is to be redrawn
  */
  void update(BOOL bRedraw);

  /**
  @brief		update study tab property
  @return		
  */
  void  updateTabProperty(BOOL redraw);

  /**
  @brief		install style
  @param		style pointer to a study tab style
  */
  void installStyle(IStudyTabStyle* style);

  /**
  @brief		set draw manager
  @param		p pointer to study tab draw
  */
  void setDrawManager(CStudyTabDraw* p);

  /**
  @brief		access to draw manager
  @return		pointer to study tab draw
  */
  CStudyTabDraw* getDrawManager() const;

  /**
  @brief		set rearrange manager
  @param		p pointer to study rearrange
  */
  void setRearrangeManager(IStudyTabRearrange* p);

  /**
  @brief		access to rearrange manager
  @return		pointer to study tab rearrange
  */
  IStudyTabRearrange* getRearrangleManager() const;

  /**
  @brief		set behavior manager
  @param		p pointer to study tab behavior
  */
  void setBehaviorManager(IStudyTabBehavior* p);

  /**
  @brief		access to study tab behavior manager
  @return		pointer to study tab behavior manager
  */
  IStudyTabBehavior* getBehaviorManager() const;

  /**
  @brief		set tooltip manager
  @param		p pointer to study tab tooltip
  */
  void setToolTipManager(IStudyTabToolTip* p);

  /**
  @brief		access to study tab tooltip manager
  @return		pointer to study tab tooltip
  */
  IStudyTabToolTip* getToolTipManager() const;

  /**
  @brief		set system menu image
  @param		imageList pointer to system menu image list
  @return		TRUE if succeeds, FALSE if not
  */
  BOOL setSystemImageList(CImageList* imageList);

  /**
  @brief		access to system image list
  @return		pointer to system image list
  */
  const CImageList* getSystemImageList() const;

  /**
  @brief		get system image size
  @return		system image size
  */
  CSize getSystemImageSize() const;

  /**
  @brief		enable or disable tooltip
  @param		enable flag indicating whether tooltip is to be enable or disable
  */
  void enableToolTip(BOOL enable);

  /**
  @brief		check whether tooltip is enable or not
  @return		TRUE if tooltip is enable, FALSE if not
  */
  BOOL isToolTipEnalbe() const;

  /**
  @brief		get the number of items
  @return		the number of items
  */
  unsigned getNumOfItems() const;

  /**
  @brief		access to item
  @param		index the index number of item to be accessed
  @return		pointer to item if found, nullptr if not
  */
  const CStudyTabItem* getItem(unsigned index) const;

  /**
  @brief		select an item
  @param		index the index number of item to be selected
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD setSel(unsigned index);

  /**
  @brief		access to the selected item
  @return		pointer to the selected item if exist, nullptr if not
  */
  const CStudyTabItem* getSel() const;

  /**
  @brief		access to pushed item
  @return		pointer to the pushed item if exist, nullptr if not
  */
  const CStudyTabItem* getPushed() const;

  /**
  @brief		access to hovered item
  @return		pointer to the hovered item if exist nullptr if not
  */
  const CStudyTabItem* getHover() const;

  /**
  @brief		get item in the given point 
  @param		point 
  @return		pointer to item if exist, nullptr if not
  */
  const CStudyTabItem* hitTest(const CPoint& point);

  /**
  @brief		get the index number of item
  @param		item pointer to study tab item
  @return		the index number of item
  */
  int getIndex(const CStudyTabItem* item) const;

  /**
  @brief		check whether an item is exist or not
  @param		item pointer to study tab item to be checked
  @return		TRUE if exist, FALSE if not
  */
  BOOL isExist(const CStudyTabItem* item) const;

  /**
  @brief		check whether an item is visible or not
  @param		item pointer to study tab item
  @param    isPartially 
  @return		TRUE if the item is visible , FALSE if not
  */
  BOOL isItemVisible(const CStudyTabItem* item, BOOL* isPartially) const;

  /**
  @brief		shift item in a visible area
  */
  void ensureVisible(const CStudyTabItem* item);

  /**
  @brief		shift to show first(left) item
  */
  void scrollToBegin();

  /**
  @brief		shift to show last(right) item
  @param		
  @return		
  */
  void scrollToEnd();

  /**
  @brief		request to show close button
  */
  void showCloseButton(BOOL show);

  BOOL isCloseButtonVisible() const;

  void showMenuButton(BOOL show);

  BOOL isMenuButtonVisible() const;

  void showScrollButtons(BOOL show);

  BOOL areScrollButtonsVisible() const;

  CRect getItemsRect() const;

  CRect getCloseButtonRect() const;

  CRect getMenuButtonRect() const;

  CRect getScrollLeftRect() const;

  CRect getScrollRightRect() const;

  CRect getItemHorzMargin();

  CRect getCloseBtnMargin();

  CRect getMenuBtnMargin();

  CRect getLeftScrollBtnHorzMargin();

  CRect getRightScrollBtnHorzMargin();

  CToolTipCtrl* getToolTip() const;

  enum Image 
  {
    ImageClose,
    ImageMenu, ImageMenuPartial,
    ImageArrowLeft, ImageArrowLeftDisable,
    ImageArrowRight, ImageArrowRightDisable
  };

private:

  void setSel(const CStudyTabItem* item);

  void rearrange();

  int getFullItemsWidth();

  void calcItemsWidth();

  void calcItemsRect();

  BOOL isSystemButton(const CStudyTabItem* item) const;

  void StepLeft();
  void StepRight();

  void StopScrolling();

  void assignHoverItem(const CPoint& point);

  void ttnNeedText(NMTTDISPINFO* TT);

  CRect getItemRect(const CStudyTabItem* item) const;

  BOOL validateCreateParams(const CreateParams& params) const;
private:

  CImageList m_theSysImageList;
  CSize      m_theSysImageSize;

  CFont m_theFont;

  CString m_theToolTip;

  CString m_theToolTipBtnClose;
  CString m_theToolTipBtnMenu;
  CString m_theToolTipBtnLeftScroll;
  CString m_theToolTipBtnRightScroll;

  BOOL m_theVisibleCloseBtn;
  BOOL m_theVisibleMenuBtn;
  BOOL m_theVisibleScrollBtns;
  BOOL m_theToolTipEnable;

  int m_theScrollingStep;

  unsigned int m_theMaxNumOfTabs;

  CStudyTabDraw* m_theDrawManger;
  IStudyTabRearrange* m_theRearrangeManager;
  IStudyTabBehavior* m_theBehaviorManager;
  IStudyTabToolTip* m_theToolTipManager;

  const CStudyTabItem* m_theCloseBtnItem;
  const CStudyTabItem* m_theMenuBtnItem;
  const CStudyTabItem* m_theLeftScrollBtnItem;
  const CStudyTabItem* m_theRightScrollBtnItem;

  const CStudyTabItem* m_theCurSelItem;
  const CStudyTabItem* m_theHoverdItem;
  const CStudyTabItem* m_thePushedItem;

  int m_theItemsOffset, m_theMaxItemsOffset;

  BOOL m_isPartialView, m_isScrollLeftAllowd, m_isScrollRightAllowd;

  CRect m_theItemsRect;

  CRect m_theCloseBtnRect, m_theMenuBtnRect, m_theScrollLeftBtnRect, m_theScrollRightBtnRect;

  CToolTipCtrl* m_theToolTipCtrl;

  std::list<CStudyTabItem*> m_theItemList;

  MonitorResolutionType m_theResType;

  unsigned int m_theMonitorIndex;

private:
  struct Service : public IStudyTabRearrange, public IStudyTabBehavior, public IStudyTabToolTip
  {
    virtual CRect getItemHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

    virtual CRect getLeftScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

    virtual CRect getRightScrollBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

    virtual CRect getMenuBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

    virtual CRect getCloseBtnHorzMargin(CStudyTab& tabCtrl, IStudyTabRearrange& base);

    virtual const CStudyTabItem* hitTest(CStudyTab& tabCtrl, IStudyTabBehavior& base, const CPoint& point);

    virtual CToolTipCtrl* createToolTip(CStudyTab& tabCtrl, IStudyTabToolTip& base);

    CToolTipCtrl m_theToolTipCtrl;
  }m_theSerivce;

  class TabPaintDC : public CDC
  {
  private:
    DISALLOW_COPY_AND_ASSIGN(TabPaintDC);

  public:
    TabPaintDC(CDC& dstDC, const CWnd& dstWnd);

    TabPaintDC(CDC& dstDC, const CRect& dstRect);

    virtual ~TabPaintDC();

    static void enableDoubleBuffering(BOOL enable)
    {
      *getDoubleBufferingFlag() = enable;
    }

    static BOOL isDoubleBufferingEnable()
    {
      return *getDoubleBufferingFlag();
    }

  private:
    BOOL init(CDC& dstDC);

    static BOOL* getDoubleBufferingFlag()
    {
      static BOOL theEnableDoubleBuffering = TRUE;
      return &theEnableDoubleBuffering;
    }

  private:
    CDC* m_theDstDC;
    CRect m_theDstRect;

    CBitmap m_theBmpSrc;
    CBitmap* m_theOldBmp;
    BOOL m_theSuccess;
  };

protected:
	DECLARE_MESSAGE_MAP()
public:
  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnDestroy();
  afx_msg void OnSize(UINT nType, int cx, int cy);
  afx_msg void OnPaint();
  afx_msg BOOL OnEraseBkgnd(CDC* pDC);
  afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
  afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  afx_msg void OnMouseLeave();
  afx_msg void OnTimer(UINT_PTR nIDEvent);
  afx_msg void OnCaptureChanged(CWnd *pWnd);
};


